# coding:utf-8
from contextlib import nullcontext
from datetime import datetime
import re
import json
from typing import Dict, List
import tushare as ts
import pandas as pd
from PyQt6.QtCore import Qt, QEasingCurve, QUrl
from PyQt6.QtGui import QPixmap
from PyQt6.QtWidgets import QWidget, QHBoxLayout
from qfluentwidgets import (
    SingleDirectionScrollArea,
    SmoothScrollArea,
    ToolTipFilter,
    PixmapLabel,
    ScrollArea,
    ImageLabel,
    HorizontalPipsPager,
    PipsScrollButtonDisplayMode,
    VerticalPipsPager,
)
from qframelesswindow.webengine import FramelessWebEngineView

from common.enum.strategy_group_enum import StrategyGroup
from dto.stock_info_monitor import AntMonitorStockInfo
from dto.strategy_stock_day import StrategyStockDay
from service.das.stock_day_das import StockDateDayDas
from service.init_service import RefreshStockInit
from service.stock_service import StockMainService
from service.strategy_query_service import StrategyViewQueryService
from views.template_page_view import BasePageTemplateView, ComponentConfig, TableDataDto

from .base_gallery_view import GalleryInterface
from .common.translator import Translator
from common.utils.JsonReplace import JsonPlaceholderReplacer


class StockDayView(BasePageTemplateView):
    """Scroll interface"""

    def __init__(self, parent=None):
        t = Translator()
        super().__init__("StockDayView", parent=parent)

        # 添加一个报表

    def doInitAndUpdate(self):

        # 初始化搜索条件
        self.searchKey = self.getScrollToCardData()
        if self.searchKey is None:
            self.searchKey = "000001.SH"

        self.strategyService = StrategyViewQueryService()
        self.finalResult = self.strategyService.searchFinalResultByCode(self.searchKey)

        component_configs = [
            ComponentConfig(
                "QLineEdit", self.search_callback, kwargs={"placeholder": "Search..."}
            ),
            ComponentConfig(
                "PushButton",
                self.update_current,
                kwargs={"name": "刷新当前", "width": 150},
            ),
        ]

        self.addTopOperation("搜索栏", component_configs, self.getBaseParam)

        levelMain_HLayout = QHBoxLayout()
        self.addKeyValueFormTemplate(
            "个股综合信息",
            self.getMainKeyMapTableRisk,
            self.getBaseParam,
            1,
            levelMain_HLayout,
        )

        self.addEchatTemplate(
            "个股评分",
            "stock_bingtu",
            self.exchangeBingtuData,
            self.getBaseParam,
            1,
            levelMain_HLayout,
        )
        self.addOutLayout(levelMain_HLayout)

        self.addTableTemplate(
            "个股风险报表", self.tableMainStockRisk, self.getBaseParam, 1
        )
        self.addEchatTemplate(
            "个股行情", "stock_day", self.getStockDayData, self.getBaseParam, 1
        )

    def doUpdatePage(self):
        self.searchKey = self.getScrollToCardData()
        self.search_callback(self.searchKey)

    def search_callback(self, searchKey: str):
        self.searchKey = searchKey
        self.search_and_refresh()

    def update_current(self):
        refreshInit = RefreshStockInit()
        refreshInit.process_stock_flow(self.searchKey)
        self.search_and_refresh()

    def search_and_refresh(self):
        AntLogger.info(f"刷新个股信息 {self.searchKey}")
        self.finalResult = self.strategyService.searchFinalResultByCode(self.searchKey)
        self.refreshDataForTemplate("个股综合信息")
        self.refreshDataForTemplate("个股评分")
        self.refreshDataForTemplate("个股风险报表")
        self.refreshDataForTemplate("个股行情")

    def getMainKeyMapTableRisk(self, params: Dict[str, str]) -> str:
        """大盘 Risk Key-value 报表数据"""
        finalResult = self.finalResult
        stock_info = finalResult.stock_info
        return {
            "股票代码": stock_info.stock_code if stock_info else "未知",
            "股票名称": stock_info.stock_name if stock_info else "未知",
            "最新股价": finalResult.latest_price,
            "计算总得分": finalResult.total_score,
            "风险等级": finalResult.risk_level,
            "关注等级": finalResult.focus_level,
            "股票积分": stock_info.stock_final_point if stock_info else None,
            "关注等级（原始）": stock_info.stock_focus_level if stock_info else None,
            "风险等级（原始）": stock_info.stock_risk_level if stock_info else None,
            "更新时间": (
                stock_info.modified_date.strftime("%Y-%m-%d %H:%M:%S")
                if stock_info and stock_info.modified_date
                else None
            ),
        }

    def tableMainStockRisk(self, params: Dict[str, str]) -> str:
        try:
            # 定义表格头
            table_header = [
                "策略名称",
                "风险等级",
                "策略分组",
                "分析天数",
                "节点得分",
                "描述",
            ]

            # 填充表格数据
            table_data = []
            for assessment in self.finalResult.risk_assessments:
                row = [
                    assessment.config.strategy_name,
                    str(assessment.config.strategy_level),
                    (
                        "风险型"
                        if assessment.config.strategy_group == StrategyGroup.RISK
                        else "关注型"
                    ),
                    str(assessment.config.analysis_day),
                    str(assessment.node_point),
                    assessment.description,
                ]
                table_data.append(row)

                # 定义操作按钮回调函数

            def example_callback(stock_code: str) -> str:
                return f"查看股票 {stock_code} 的详情"

            # 创建 TableDataDto 对象
            table_item_fun = [{"详情": example_callback}]
            return TableDataDto(
                table_header=table_header,
                table_data=table_data,
                table_item_fun=table_item_fun,
            )

        except Exception as e:
            AntLogger.info(f"转换时出错: {e}")
            # 返回一个空的 TableDataDto 对象
            return TableDataDto(table_header=[], table_data=[], table_item_fun=[])

    def getBaseParam(self) -> Dict[str, str]:
        return {"stockCode": "100001"}

    def getStockDayData(self, jsonData: str, params: Dict[str, str]) -> str:
        if self.searchKey is not None and self.searchKey != "":
            AntLogger.info(f"校验通过{self.searchKey}")

            stock_data = self.get_stock_data()
            stock_info = self.get_stock_info()
            dates_data = self.get_datas(stock_data)
            kline_data = self.get_kline_data(stock_data)
            point_data = self.get_point_data(stock_data)
            mark_data = self.get_markline_data(stock_data)

            replacer = JsonPlaceholderReplacer(jsonData)

            replacer.replace_placeholder("__DATAS__", dates_data)
            # 时间轴
            replacer.replace_placeholder(
                "__STOCK_NAME__", stock_info.stock_name + "[ " + self.searchKey + " ]"
            )
            # 主线数据
            replacer.replace_placeholder("__STOCK_DATA__", kline_data)
            # 标记点数据
            replacer.replace_placeholder("__POINT_DATA__", point_data)
            # 辅助线数据
            replacer.replace_placeholder("__MARK_DATA__", mark_data)
            return replacer.get_modified_json()
        else:
            return jsonData

    def exchangeBingtuData(self, jsonData: str, params: Dict[str, str]) -> str:
        stock_data = self.getStockBingTuData()
        replacer = JsonPlaceholderReplacer(jsonData)
        replacer.replace_placeholder("__STOCK_DATA__", stock_data)
        return replacer.get_modified_json()

    def getStockBingTuData(self) -> str:
        # 初始化输出的结果列表
        result = self.finalResult
        output = []

        # 定义风险和关注的父结构
        risk_section = {
            "name": "风险",
            "value": 0,  # 初始化为 0，后面将根据策略得分来累加
            "children": [],
        }
        focus_section = {
            "name": "关注",
            "value": 0,  # 初始化为 0，后面将根据策略得分来累加
            "children": [],
        }

        # 临时存储各策略类型的分数
        risk_strategies = {}
        focus_strategies = {}

        # 遍历策略评估结果，按照风险和关注类型进行分类
        for assessment in result.risk_assessments:
            strategy_name = assessment.config.strategy_name
            node_point = assessment.node_point
            strategy_type = assessment.config.strategy_type

            # 分类并累加分数
            if assessment.config.strategy_group == StrategyGroup.RISK:
                # 按策略类型分组
                if strategy_type not in risk_strategies:
                    risk_strategies[strategy_type] = {
                        "name": strategy_type.description,  # 假设 strategy_type 是一个枚举，使用 description
                        "value": 0,
                        "children": [],
                    }
                risk_strategies[strategy_type]["value"] += abs(node_point)
                risk_strategies[strategy_type]["children"].append(
                    {"name": strategy_name, "value": abs(node_point)}
                )
            elif assessment.config.strategy_group == StrategyGroup.ATTENTION:
                # 按策略类型分组
                if strategy_type not in focus_strategies:
                    focus_strategies[strategy_type] = {
                        "name": strategy_type.description,  # 假设 strategy_type 是一个枚举，使用 description
                        "value": 0,
                        "children": [],
                    }
                focus_strategies[strategy_type]["value"] += abs(node_point)
                focus_strategies[strategy_type]["children"].append(
                    {"name": strategy_name, "value": abs(node_point)}
                )

        # 计算“风险”部分的总分
        risk_total_value = sum(strategy_info["value"] for strategy_info in risk_strategies.values())
        risk_section["value"] = risk_total_value

        # 将统计结果加入“风险”部分
        for strategy_type, strategy_info in risk_strategies.items():
            risk_section["children"].append(strategy_info)

        # 计算“关注”部分的总分
        focus_total_value = sum(strategy_info["value"] for strategy_info in focus_strategies.values())
        focus_section["value"] = focus_total_value

        # 将统计结果加入“关注”部分
        for strategy_type, strategy_info in focus_strategies.items():
            focus_section["children"].append(strategy_info)

        # 将“风险”和“关注”加入最终的输出列表
        output.append(risk_section)
        output.append(focus_section)

        return output


    def get_stock_data(self) -> List[StrategyStockDay]:

        # 从 DAS 获取所有日K数据
        stockDayDas = StockDateDayDas()
        day_data_list = sorted(
            stockDayDas.search_by_day_all(self.searchKey),
            key=lambda x: x.trade_date,
            reverse=False,
        )

        # 提取需要的列（日期、开盘、收盘、最高、最低）
        return day_data_list

    def get_stock_info(self) -> AntMonitorStockInfo:
        stockInfoService = StockMainService()
        return stockInfoService.getByStockCode(self.searchKey)

    def get_kline_data(self, stock_data: List[StrategyStockDay]) -> List[List[float]]:
        """
        生成 K 线图所需的数据数组
        :param stock_data: 包含股票每日交易数据的列表
        :return: K 线图所需的数组 [[open, close, low, high], ...]
        """
        return [[row.open, row.close, row.low, row.high] for row in stock_data]

    def get_datas(self, stock_data: List[StrategyStockDay]):
        return [
            datetime.strptime(str(item.trade_date), "%Y%m%d").strftime("%Y-%m-%d")
            for item in stock_data
        ]

    def get_point_data(self, stock_data):
        return [
            {"name": "highest value", "type": "max", "valueDim": "highest"},
            {"name": "lowest value", "type": "min", "valueDim": "lowest"},
        ]

    def get_markline_data(self, stock_data: List[StrategyStockDay]) -> dict:
        """
        生成 markLine 数据，用于标注收盘价的平均值
        :param stock_data: 包含股票每日交易数据的列表
        :return: 包含平均线数据的字典
        """
        # 计算收盘价平均值
        try:
            average_price = sum(item.close for item in stock_data) / len(stock_data)
        except ZeroDivisionError:
            average_price = 0

        # 构造 markLine 数据
        return {
            "data": [
                {
                    "yAxis": average_price,  # 设置 y 轴值为均值
                    "name": "平均值",
                    "lineStyle": {
                        "color": "#FF0000",  # 虚线颜色
                        "type": "dashed",  # 线条类型：虚线
                        "width": 2,  # 线条宽度
                    },
                    "label": {
                        "formatter": f"平均值: {average_price:.2f}",  # 显示均值
                        "position": "end",  # 文本位置
                        "color": "#FF0000",  # 文本颜色
                    },
                }
            ]
        }
